home *** CD-ROM | disk | FTP | other *** search
- /*
- TimeVideo.c
- Copyright © Denis G. Pelli, 1992, 1993
-
- TimeVideo does a thorough test of the timing and synchronization of each video
- screen, as well as the integrity of the clut hardware and software, and saves
- the results in self-explanatory text file, “TimeVideo results”. A discussion
- of movies, lookup table animation, and synchronization appears in the
- VideoToolbox “Video synch” file. The many video driver bugs uncovered by
- TimeVideo and its predecessors are reported in that file. (For example, the
- TrueVision NuVista driver assumes zero start in 16- and 32-bit modes.) Please
- add your results by emailing your “TimeVideo report” to denis_pelli@isr.syr.edu.
-
- Despite Apple's rules that require it, a few video drivers don't allow you to
- read the clut (i.e. use GDGetEntries), or crash if you attempt it. GDGetEntries
- (in GDVideo.c) checks against a list of known offenders and returns a statusErr
- is the call is not usable. If we can't use GDGetEntries then we fall back to a
- visual test of the clut, comparing a particular way of loading the clut
- against the standard way of loading the clut. Any visible change between these
- two conditions suggests an error in the non-standard way of loading the clut.
-
- BUGS:
- Version 1.0 hung up on a PowerBook 170 with an Envisio video adapter. I didn't
- have a chance to figure out why. It works fine on my ordinary PowerBook 170.
-
- HISTORY:
- 8/23/92 dgp wrote it, based on my TimeCPU.c
- 8/26/92 dgp print the driver version only if it's nonzero.
- added summary at end of printout.
- 9/9/92 dgp changed printout of system vbl rate from %.1f to %.2f
- Added movie rate to measurements and printout.
- 9/15/92 dgp made compatible with System 6.04. Added header to results file.
- 9/17/92 dgp Added QUICKLY switch, to select CopyBits or CopyBitsQuickly.
- 10/5/92 dgp cosmetic changes
- 10/6/92 dgp report program version. Use frames/clut update as the criterion for summary.
- 10/9/92 dgp Fixed summary. Too slow means MORE than one frame per clut update.
- Fixed restoration of clut in direct modes (i.e. 16 and 32 bit modes).
- Renamed to GDRestoreDeviceClut and put it in GDVideo.c.
- 10/13/92 dgp Tom Busey reported that frames were going uncounted
- during the clut timing, which seems to be a problem with some video drivers.
- TimeVideo now reports a frame count based solely on timing in secs and
- the separately measured frame rate, which seems to be a reliable.
- It also double checks the timing in secs vs frames, and if
- it finds a discrepancy, prints a warning to the screen & file.
- 10/20/92 dgp Added VBL/frame to summary.
- 12/8/92 dgp Minor editing of comments.
- 12/9/92 dgp 1.01 Added _atexit(RestoreCluts) in case user quits prematurely.
- 12/11/92 dgp 1.02 GDRestoreBlackAndWhite allocates stack space for linearTable
- only if we need it.
- 12/30/92 dgp 1.03 cosmetic changes.
- 12/30/92 dgp 1.04 Enhanced summary to account for NAN when no clut access is allowed.
- 12/30/92 dgp 1.05 Use GDClutSize().
- 1/6/93 dgp 1.06 Simplified GDRestoreBlackAndWhite, eliminated linearTable.
- 1/7/93 dgp 1.07 Included in VideoToolbox-1-93.sea
- 1/8/93 dgp 1.08 Added Info-Mac to report file.
- 1/11/93 dgp 1.09 In response to bug report from jonathan brecher, added support
- for computers that lack Color QuickDraw.
- 1/15/93 dgp 1.10 Added version resource.
- 1/18/93 dgp 1.11 Updated the explanatory text.
- 1/24/93 dgp 1.12 Updated the explanatory text.
- 2/6/93 dgp 1.13 Report ROM version.
- 2/15/93 dgp 1.14 Report ROM version as 124+6*256.
- 2/22/93 dgp 1.15 Recompiled.
- 2/27/93 dgp 1.16 Recompiled with new Identify.c.
- 3/10/93 dgp 1.17 Choose a valid mode for which to print the frame rate.
- Moved all the timing code into GDInfo.c, so this routine just prints.
- 3/12/93 dgp Reorganized the printout and added TestCluts's capabilities.
- 3/13/93 dgp Added high-priority timing.
- 3/16/93 dgp 2.0 Added visual hash inspection.
- 3/31/93 dgp 2.1 Release version, clut test seems to work.
- */
- #include "VideoToolbox.h"
- #include <Packages.h>
- #include <Traps.h>
- #include <math.h>
- #include "GDInfo.h"
- void TimeVideo(void);
- void PrintCard(FILE *o[2],GDHandle device,VideoCard *card);
- void GDRestoreBlackAndWhite(GDHandle device);
- #define VERSION "2.1"
-
- void main(void)
- {
- Require(gestaltOriginalQD);
- TimeVideo();
- }
-
- void TimeVideo(void)
- {
- long system;
- char string[1000],datafilename[]="TimeVideo results";
- FILE *o[2],*dataFile;
- int newDataFile;
- unsigned long time;
- Str255 todayStr;
- GDHandle device;
- short i,m,error,oldPixelSize,mode,cards,modes;
- double frames,s,vblPerFrame,f;
- Rect r;
- static VideoCard card[MAX_SCREENS]; // "static" will initialize to zero.
- VideoCardClutTest *clut;
- short visualTest,hashTest;
-
- StackGrow(10000);
- MaximizeConsoleHeight();
- #if THINK_C
- console_options.title="\pTimeVideo";
- #endif
- printf("\n"); // ask THINK C to initialize quickdraw
-
- sprintf(string,"Welcome to TimeVideo " VERSION "\n\n"
- "This program will thoroughly test all your video devices and save the "
- "results in the text file “%s”. Don’t be alarmed by the strange "
- "antics of your screens. Everything will soon be back to normal. Just sit back "
- "and enjoy the show.",datafilename);
- sprintf(string,"%s You may quit at any time by hitting Command-period.",string);
- printf(BreakLines(string,80));
- printf("\n\nWould you like the testing to include a visual inspection?");
- visualTest=YesOrNo(1);
- printf("\n");
- printf(BreakLines("\n"
- "TimeVideo times everything: the video frames, interrupts, and cluts. And it "
- "determines what fraction of the screen you can fill with a real-time movie shown "
- "by CopyBits() or CopyBitsQuickly(). Then it does write-then-read tests of the "
- "clut, to make sure the hardware and software, GDSetEntries or SetEntriesQuickly, "
- "are working correctly.\n\n",80));
- dataFile=fopen(datafilename,"r");
- if(dataFile!=NULL)fclose(dataFile);
- newDataFile=(dataFile==NULL);
- o[0]=stdout;
- o[1]=dataFile=fopen(datafilename,"a"); /* Append to data file */
- if(dataFile!=NULL)SetFileInfo(datafilename,'TEXT','ttxt');
- else printf("Could neither open nor create \"%s\". Perhaps your disk is locked.\n",datafilename);
- if(newDataFile){
- fprintf(dataFile,BreakLines(
- "This data file reports the timing and accuracy of all your video screens, "
- "as measured by TimeVideo, a component of the VideoToolbox.\n"
- "\nTHE VIDEO TOOLBOX\n"
- "The VideoToolbox is a "
- "collection of nearly two hundred C subroutines and several demo and utility "
- "programs written to do visual psychophysics with Macintosh computers. It's free "
- "and may not be sold without permission. It should be useful to anyone who wants "
- "to present accurately specified visual stimuli or use the Mac for psychometric "
- "experiments. The text file “Video synch” discusses all the ways of synchronizing "
- "programs to video displays and the many pitfalls to avoid. The TimeVideo "
- "application checks out the timing of all video devices in anticipation of their "
- "use in critical real-time applications, e.g. movies or lookup-table animation. "
- "Low-level routines control video timing and lookup tables, display real-time "
- "movies, and implement the luminance-control algorithms suggested by Pelli and "
- "Zhang. (D.G. Pelli and L. Zhang, 1991, Accurate control of contrast on "
- "microcomputer displays. Vision Research, 31, 1337-1350. Reprints are available.) "
- "High-level routines help analyze psychophysical experiments (e.g. graphing or "
- "maximum-likelihood fitting of psychometric data). This collection has been "
- "continually updated since 1991. Many colleagues have indicated that they are "
- "using the software in their labs. Most of the routines are Mac-specific, but "
- "some very useful routines, e.g. the luminance-control, statistics, and "
- "maximum-likelihood fitting algorithms, could easily be ported to other "
- "computers. To get the latest version of the VideoToolbox, just send me your "
- "mailing address, and I’ll mail you a disk. Or download “VideoToolbox.sea” (a "
- "self-extracting archive) electronically from the Info-Mac or MacPsych archives. "
- "The ftp servers are called sumex-aim.stanford.edu [36.44.0.6] (look in "
- "info-mac/source/c) and ftp.stolaf.edu [130.71.128.9] (look in the pub/macpsych "
- "directory). Log in as “anonymous”; any password will do.\n",80));
- fprintf(dataFile,
- "Denis Pelli, Professor of Neuroscience\n"
- "Institute for Sensory Research, Syracuse University, Syracuse, NY 13244-5290, USA\n"
- "denis_pelli@isr.syr.edu\n");
- fprintf(dataFile,BreakLines(
- "\nTIME VIDEO\n"
- "For each video card, TimeVideo measures the video frame rate, frequency of VBL "
- "interrupts (supposed to be one per frame), how long it takes to load the clut, "
- "and how much of the screen you can fill with a real-time one-image-per-frame "
- "movie shown by CopyBits() or CopyBitsQuickly(). It then performs a random "
- "write-then-read test of the Color Lookup Table (clut). This tests the clut "
- "memory hardware and the software used to write and read the clut. We test "
- "writing by GDSetEntries(), which passes the request on to the video driver, and "
- "we also test writing by SetEntriesQuickly(), which accesses the hardware "
- "directly. In either case, the clut is read by GDGetEntries(), which passes the "
- "request on to the video driver. The testing is thorough; many video devices fail "
- "at least part of the test. All the driver errors uncovered to date appear in the "
- "VideoToolbox “Video synch” text file. Add your results by emailing this file to "
- "denis_pelli@isr.syr.edu\n"
- "\nGLOSSARY\n"
- "A video frame is a refresh of your video screen. To show a movie, you will want "
- "to reload the image once per frame; the table shows how big that image can be, "
- "as a fraction of the screen area, and still be reloaded once per frame. "
- "(Some video cards have multiple video “pages” that can be switched by "
- "calling GDSetMode(), though I've never tried it.) A “VBL” "
- "interrupt is produced by your video card driver, nominally once per frame, but "
- "some video drivers produce more, which is poor, but not serious. (The "
- "VBLInstall.c program will deal with it.) Suppressed interrupts during clut "
- "updates are bad. It means that the driver disables the VBL interrupt for too "
- "long while it’s loading the clut. This will throw off any interrupt-based "
- "attempt to count frames. The clut is the color lookup table of your video card. "
- "Lookup table animation, e.g. for temporal modulation of contrast, requires that "
- "you reload the clut once per frame, so it’s very important that this be fast "
- "enough. "
- "The first call to SetEntriesQuickly() for each device is slow--a cache is "
- "filled; the reported times are for subsequent calls. "
- "Each video card can be in “Color” or “Gray” mode, as set by the Control "
- "Panel:Monitors, the Macintosh Toolbox call SetDepth, or the VideoToolbox call "
- "GDSetGray. In “Gray” mode all colors are transformed to luminance-equivalent "
- "grays. The clut tests try loading the clut serially, one entry at a time, and "
- "all at once; some video drivers fail the serial test because they don’t cope "
- "well with a nonzero “start” value for the entry index. For more explanation see "
- "the text file called “Video synch” on the VideoToolbox disk.\n"
- "\n"
- "“ok”= the clut passed all tests.\n"
- "“!gray”= the clut was nominally in gray mode, but only passed the color test.\n"
- "“!color”= the clut was nominally in color mode, but only passed the gray test.\n"
- "“!serial”= clut passed when loaded all at once, but failed when loaded serially.\n"
- "“bad”= the clut produced some other pattern of errors, reported explicitly.\n"
- "SetEntriesQuickly: “!gray” is ok, and “!serial” is ok on the Quadra.\n"
- "\nThis is a TeachText file, "
- "but you may prefer to open it from THINK C, or a word processor, because the columns "
- "in the tables will only align properly if displayed in a monospaced font.\n\n",80));
- }
- ffprintf(o,"TimeVideo version " VERSION "\n");
- GetDateTime(&time);
- IUDateString(time,longDate,todayStr);
- ffprintf(o,"%#s.\n",todayStr);
-
- // Timer.c requires the Revised Time Manager, which appeared in System 6.0.3.
- // SetDepth() is part of the "new" Palette Manager, which appeared in System 6.0.5.
- Gestalt(gestaltSystemVersion,&system);
- if(system<0x605) {
- PrintfExit("Sorry. Your System is too old; I need at least System 6.0.5.\n");
- }
-
- ffprintf(o,"%s\n",BreakLines(IdentifyMachine(),80));
- ffprintf(o,"Tick rate is %.1f Hz.",TickRate());
- ffprintf(o," System-based VBL rate is %.1f Hz.\n",GDFrameRate(NULL));
- if(QD8Exists())_atexit(RestoreCluts);// In case user quits prematurely.
- for(i=0;;i++){
- if(QD8Exists()){
- device=GetScreenDevice(i);
- if(device==NULL)break;
- oldPixelSize=(**(**device).gdPMap).pixelSize;
- }else device==NULL;
- ffprintf(o,"\n%s\n",BreakLines(IdentifyVideo(device),80));
- printf("Getting card info. . . \r");
- error=GDInfo(device,&card[i]);
- card[i].visual=hashTest=visualTest;
- for(m=0;m<6;m++){
- card[i].depth[m].pixelSize=0;
- if(QD8Exists()){
- if(!HasDepth(device,1<<m,0,0))continue;
- error=SetDepth(device,1<<m,0,0);
- card[i].mode=(**device).gdMode;
- if(error)continue;
- }else if(m>0)continue;
- card[i].m=m;
- card[i].depth[m].pixelSize=1<<m;
- error=GDTime(device,&card[i]);
- printf("%d-bit pixels: testing clut: GDSetEntries . . . \r"
- ,card[i].depth[m].pixelSize);
- card[i].depth[m].clut.hashTest=hashTest;
- card[i].depth[m].clutQuickly.hashTest=hashTest;
- hashTest=0; // Only do the hash test at one depth
- card[i].depth[m].clut.tests=0;
- card[i].depth[m].clutQuickly.tests=0;
- error=TestClut(o,device,0,&card[i]);
- error=TestClut(o,device,testClutSeriallyFlag,&card[i]);
- error=TestClutHash(device,GDSetEntriesByType,&card[i].depth[m].clut);
- printf("%d-bit pixels: testing clut: SetEntriesQuickly . . . \r",card[i].depth[m].pixelSize);
- error=TestClut(o,device,testClutQuicklyFlag,&card[i]);
- error=TestClut(o,device,testClutQuicklyFlag|testClutSeriallyFlag,&card[i]);
- error=TestClutHash(device,SetEntriesQuickly,&card[i].depth[m].clutQuickly);
- printf(" \r");
- }
- if(QD8Exists())error=SetDepth(device,oldPixelSize,0,0);
- ffprintf(o,"%dx%d pixels. ",card[i].width,card[i].height);
- if(card->isGray)ffprintf(o,"Gray mode.\n");
- else ffprintf(o,"Color mode.\n");
- PrintCard(o,device,&card[i]);
- if(!QD8Exists())break;
- }
- cards=i;
- if(GDVersion(device)==100
- && EqualString("\p.Display_Video_Apple_RBV1",GDName(device),1,1)){
- ffprintf(o,
- "NOTE: the built-in driver in the Mac IIci (.Display_Video_Apple_RBV1 version 0)\n"
- "has a bug that causes it to crash if you attempt to read the clut. A temporary\n"
- "patch has been applied that has fixed the driver until the next reboot, as\n"
- "explained in the VideoToolbox file “Video synch”.\n");
- }
- fprintf(o[1],"\n\n");
- if(dataFile!=NULL){
- fclose(dataFile);
- sprintf(string,"\nThe text file “%s” explains all the results.\n",datafilename);
- printf(BreakLines(string,80));
- }
- }
-
- void PrintCard(FILE *o[2],GDHandle device,VideoCard *card)
- {
- short i,m=card->m,hashTest,visualTest;
- char string[100];
- static char s1[]="%-33s",s2[]="%6s",s3[]=" %-9s\n";
- VideoCardClutTest *clut;
-
- ffprintf(o,s1,"pixel size");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%d ",card->depth[m].pixelSize);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"bits");
-
- ffprintf(o,s1,"pages");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%d ",card->depth[m].pages);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
-
- ffprintf(o,s1,"frame rate");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.1f ",card->depth[m].frameRate);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"Hz");
-
- ffprintf(o,s1,"interrupts per frame");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.1f ",card->depth[m].vblPerFrame);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
-
- ffprintf(o,s1,"CopyBits movie size");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.2f",card->depth[m].movieRate/card->depth[m].frameRate);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"screen");
-
- ffprintf(o,s1,"CopyBitsQuickly movie size");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.2f",card->depth[m].movieRateQuickly/card->depth[m].frameRate);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"screen");
-
- ffprintf(o,s1,"CopyBits data rate");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.2f",card->depth[m].movieRate
- *card->depth[m].pixelSize
- *card->width*card->height/8./1024./1024.);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"MB/s");
-
- ffprintf(o,s1,"CopyBitsQuickly data rate");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.2f",card->depth[m].movieRateQuickly
- *card->depth[m].pixelSize
- *card->width*card->height/8./1024./1024.);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"MB/s");
-
- if(card->gdType!=fixedType){
- ffprintf(o,s1,"GDSetEntries duration");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.2f",card->depth[m].framesPerClutUpdate);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"frames");
-
- ffprintf(o,s1,"GDSetEntries suppresses ints. for");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.1f ",card->depth[m].missingFramesPerClutUpdate);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"frames");
-
- ffprintf(o,s1,"GDSetEntriesHighPriority duration");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.2f",card->depth[m].framesPerClutUpdateHighPriority);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"frames");
-
- #if 0
- // This is just for debugging, since it must equal the duration.
- ffprintf(o,s1,"GDSetEntriesHighPriority suppr...");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.1f ",card->depth[m].missingFramesPerClutUpdateHighPriority);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"frames");
- #endif
-
- if(card->setEntriesQuickly){
- ffprintf(o,s1,"SetEntriesQuickly duration");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- sprintf(string,"%.2f",card->depth[m].framesPerClutUpdateQuickly);
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"frames");
- }
-
- hashTest=0;
- for(m=0;m<6;m++)if(card->depth[m].pixelSize)
- if(card->depth[m].clut.hashTest)hashTest=1;
- if(hashTest){
- ffprintf(o,s1,"GDSetEntries hash inspection");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- if(card->depth[m].clut.hashTest){
- if(card->depth[m].clut.hash)sprintf(string,"fail");
- else sprintf(string,"pass");
- }else sprintf(string,"");
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
- }
-
- if(card->setEntriesQuickly){
- hashTest=0;
- for(m=0;m<6;m++)if(card->depth[m].pixelSize)
- if(card->depth[m].clutQuickly.hashTest)hashTest=1;
- if(hashTest){
- ffprintf(o,s1,"SetEntriesQuickly hash inspection");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- if(card->depth[m].clutQuickly.hashTest){
- if(card->depth[m].clutQuickly.hash)sprintf(string,"fail");
- else sprintf(string,"pass");
- }else sprintf(string,"");
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
- }
- }
-
- ffprintf(o,s1,"GDSetEntries write-read test");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- clut=&card->depth[m].clut;
- if(!card->isGray && clut->color.errors){
- if(!clut->gray.errors)sprintf(string,"!color");
- else if(!clut->color.zeroStartErrors)sprintf(string,"!serial");
- else sprintf(string,"bad");
- } else if(card->isGray && clut->gray.errors){
- if(!clut->color.errors)sprintf(string,"!gray");
- else if(!clut->gray.zeroStartErrors)sprintf(string,"!serial");
- else sprintf(string,"bad");
- }else sprintf(string,"ok ");
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
-
- visualTest=0;
- for(m=0;m<6;m++)if(card->depth[m].pixelSize)
- if(card->depth[m].clut.visual.tests)visualTest=1;
- if(visualTest){
- ffprintf(o,s1,"GDSetEntries visual comparison");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- clut=&card->depth[m].clut;
- if(clut->visual.tests){
- if(clut->visual.errors){
- if(!clut->visual.zeroStartErrors)sprintf(string,"!serial");
- else sprintf(string,"fail");
- }else sprintf(string,"pass");
- }else sprintf(string,"");
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
- }
-
- if(card->setEntriesQuickly){
- ffprintf(o,s1,"SetEntriesQuickly write-read test");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- clut=&card->depth[m].clutQuickly;
- if(!card->isGray && clut->color.errors){
- if(!clut->gray.errors)sprintf(string,"!color");
- else if(!clut->color.zeroStartErrors)sprintf(string,"!serial");
- else sprintf(string,"bad");
- } else if(card->isGray && clut->gray.errors){
- if(!clut->color.errors)sprintf(string,"!gray");
- else if(!clut->gray.zeroStartErrors)sprintf(string,"!serial");
- else sprintf(string,"bad");
- }else sprintf(string,"ok ");
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
- }
-
- visualTest=0;
- for(m=0;m<6;m++)if(card->depth[m].pixelSize)
- if(card->depth[m].clutQuickly.visual.tests)visualTest=1;
- if(visualTest){
- ffprintf(o,s1,"GDSetEntriesQuickly visual comparison");
- for(m=0;m<6;m++)if(card->depth[m].pixelSize){
- clut=&card->depth[m].clutQuickly;
- if(clut->visual.tests){
- if(clut->visual.errors){
- if(!clut->visual.zeroStartErrors)sprintf(string,"!serial");
- else sprintf(string,"fail");
- }else sprintf(string,"pass");
- }else sprintf(string,"");
- ffprintf(o,s2,string);
- }
- ffprintf(o,s3,"");
- }
- }
- for(i=0;i<2;i++)if(o[i]!=NULL)fflush(o[i]); // Save to disk, just in case.
- }
-
- void GDRestoreBlackAndWhite(GDHandle device)
- // Restore the first & last clut entries (white & black) for
- // a clut whose mode need not correspond to what QuickDraw thinks, as
- // recorded in the device's GDHandle.
- {
- short mode,colors,error;
- ColorSpec white={255,0xffff,0xffff,0xffff},black={0,0,0,0};
-
- colors=GDClutSize(device);
- GDGetMode(device,&mode,NULL,NULL);
- if(mode<sixteenBitMode){
- error=GDSetEntries(device,0,0,&white);
- error=GDSetEntries(device,colors-1,0,&black-(colors-1));
- }else{
- error=GDDirectSetEntries(device,0,0,&black);
- error=GDDirectSetEntries(device,colors-1,0,&white-(colors-1));
- }
- }
-
-
-